
var _ :any={}

_.each = function (list, callback) {
  for (var i = 0, len = list.length; i < len; i++) {
    callback(list[i], i)
  }
}

/**
 * Shallowly copy properties to object
 * @param {Object} dest
 * @param {Object} src
 * @return {Object} - The result of extending `src` to `dest`.
 */

_.extend = function (dest, src) {
  for (var key in src) {
    if (src.hasOwnProperty(key)) {
      dest[key] = src[key]
    }
  }
  return dest
}
declare var process;
declare var window;
if (process.env.NODE_ENV) {
  _.nextTick = process.nextTick
} else {
  var nextTick = window.requestAnimationFrame ||
    window.webkitRequestAnimationFrame ||
    window.mozRequestAnimationFrame ||
    window.oRequestAnimationFrame ||
    window.msRequestAnimationFrame

  if (nextTick) {
    _.nextTick = function () {
      nextTick.apply(window, arguments)
    }
  } else {
    _.nextTick = function (func) {
      // for IE, setTimeout is a cool object instead of function
      // so you cannot simply use nextTick.apply
      setTimeout(func)
    }
  }
}
function inc (indent) {
  return indent + '  '
}
var keyIndex = 0

function getKey () {
  return 'key' + keyIndex++
}

export class CodeGen{
    nodeIndex:number;
    lines:string[];
    body:string;
    constructor(astRoot){
        this.nodeIndex=1;
        this.lines=[`var node0={children:[]}`];
        this.walkRoot(astRoot);
        this.lines.push(`return _el_("div",{},node0.children)`);
        this.body=this.lines.join("\n");
    }
    private  walkRoot(astRoot) {
        this.walk(astRoot,' ','0');
    }
    private walk(node,indent,parentIndex) {
        if (typeof node=='string') {
            return this.genString(node,indent,parentIndex);
        }else{
            //Todo gen object
            return this['gen' + node.type](node, indent, parentIndex)
        }
    }
    private genStat(node, indent, parentIndex) {
        var self = this
        _.each(node.members, function (item) {
            self.walk(item, indent, parentIndex)
        })
    }
    private genIfStat (node, indent, parentIndex) {
        var expr = node.label.replace(/(^\{\s*if\s*)|(\s*\}$)/g, '')
        this.lines.push('\n' + indent + 'if (' + expr + ') {')
        if (node.body) {
            this.walk(node.body, inc(indent), parentIndex)
        }
        if (node.elseifs) {
            var self = this
            _.each(node.elseifs, function (elseif) {
            self.walk(elseif, indent, parentIndex)
            })
        }
        if (node.elsebody) {
            this.lines.push(indent + '} else {')
            this.walk(node.elsebody, inc(indent), parentIndex)
        }
        this.lines.push(indent + '}\n')
    }
    private genElseIf (node, indent, parentIndex) {
        var expr = node.label.replace(/(^\{\s*else\s*if\s*)|(\s*\}$)/g, '')
        this.lines.push(indent + '} else if (' + expr + ') {')
        if (node.body) {
            this.walk(node.body, inc(indent), parentIndex)
        }
    }
    genEachStat (node, indent, parentIndex) {
        debugger
        var expr = node.label.replace(/(^\{\s*each\s*)|(\s*\}$)/g, '')
        var tokens = expr.split(/\s+/)
        var list = tokens[0]
        var item = tokens[2]
        var key = tokens[3] || getKey()
        this.lines.push(
            '\n' +
            indent +
            'for (var ' + key + ' = 0, len = ' + list + '.length; ' + key + ' < len; ' + key + '++) {'
        )
        this.lines.push(inc(indent) + 'var ' + item + ' = ' + list + '[' + key + '];')
        if (node.body) {
            this.walk(node.body, inc(indent), parentIndex)
        }
        this.lines.push(indent + '}\n')
    }
     genNode(node, indent, parentIndex) {
        var currentIndex = this.nodeIndex++
        var nodeName = 'node' + currentIndex
        this.lines.push(indent + 'var ' + nodeName + ' = {children: []};')
        if (node.body) {
            this.walk(node.body, indent, currentIndex)
        }
        this.lines.push(
            indent + nodeName + ' = _el_("' + node.name +
            '", ' + this.getAttrs(node) + ', ' + nodeName + '.children);'
        )
        this.lines.push(
            indent +
            'node' + parentIndex + '.children.push(node' + currentIndex + ');'
        )
    }
    getAttrs (node) {
        var str = '{'
        var attrs = node.attributes
        var i = 0;
        for (var key in attrs) {
            var attrStr = this.getInterpolation(attrs[key])
            if (i++ != 0) {
            str += (', ' + key + ': ' + attrStr)
            } else {
            str += (key + ': ' + attrStr)
            }
        }
        str += '}'
        return str;
    }

    private genString(node,indent,parentIndex) {
        let line=indent+'node'+parentIndex+'.children.push(' +this.getInterpolation(node) + ')';
        line=line.replace('\n','\\n');
        this.lines.push(line);
    }
    private getInterpolation (node) {
        var reg = /\{[\s\S]+?\}/g
        var inters = node.match(reg)
        var strs = node.split(reg)
        if (!inters) return ['"', '"'].join(node)
        var last = strs[strs.length - 1]
        strs.splice(strs.length - 1, 1)
        var ret = ''
        _.each(strs, function (str, i) {
            ret += ('"' + str + '" + ')
            ret += (
            '(' + inters[i].replace(/[\{\}]/g, '') + ') + '
            )
        })
        ret += ('"' + last + '"')
        return ret
    //    node= node.replace(/\{/g,"(");
    //    node=node.replace(/\}/g,")");
    //    return node;
    }
}